home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / gwyn-dir-lib < prev    next >
Encoding:
Internet Message Format  |  1987-04-30  |  44.7 KB

  1. Subject:  v09i065:  New directory-access library
  2. Newsgroups: mod.sources, comp.sources.unix
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: gwyn@brl.arpa <Doug Gwyn>
  6. Mod.sources: Volume 9, Issue 65
  7. Archive-name: gwyn-dir-lib
  8.  
  9. [  This is great package:  it almost seems that, between Doug and
  10.    Henry Spencer, the community will have a complete "free" POSIX
  11.    C library.  (No quibbles about legal meaning of free, please.)
  12.    I repacked the archive to bullet-proof against things like initial
  13.    periods in the manpage.  --r$ ]
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line,
  17. # then unpack it by saving it in a file and typing "sh file".
  18. # If this archive is complete, you will see the message:
  19. #        "End of shell archive."
  20. # Contents:  INSTALL NOTES closedir.c directory.3c dirent.4 dirent.h
  21. #   getdents.2 getdents.c opendir.c readdir.c rewinddir.c seekdir.c
  22. #   sys._dir.h sys.dirent.h telldir.c testdir.c
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. echo shar: Extracting \"INSTALL\" \(5490 characters\)
  25. if test -f INSTALL ; then 
  26.   echo shar: Will not over-write existing file \"INSTALL\"
  27. else
  28. sed "s/^X//" >INSTALL <<'END_OF_INSTALL'
  29. X
  30. X
  31. X            INSTALLATION INSTRUCTIONS
  32. X
  33. X
  34. XThe following instructions are for systems resembling Ninth Edition UNIX, with
  35. Xhints about dealing with variations you may encounter for your specific system.
  36. XInstallation should be done only by someone who is comfortable with modifying
  37. Xthe standard C library and header files.
  38. X
  39. XIf your system already includes directory access routines, you should replace
  40. Xthem with this package.  We're trying to get this standardized; see the
  41. Xdiscussion in the NOTES file.
  42. X
  43. XI have tried to make the source code as generic as possible, but if your system
  44. Xpredates Seventh Edition UNIX you will have problems.
  45. X
  46. XDISCLAIMER:  Although I believe the code and procedures described here to be
  47. Xcorrect, I make no warranty of any kind, and you are advised to perform your
  48. Xown careful testing before making any substantial change like this to your
  49. Xprogramming environment.
  50. X
  51. X
  52. X0)  For antique systems that do not support C's "void" data type, edit the file
  53. X    sys.dirent.h to add the following:
  54. X
  55. X    typedef int        void;    /* good enough for govt work */
  56. X
  57. X    If for some reason your <sys/types.h> doesn't define them, add the
  58. X    following to sys.dirent.h:
  59. X
  60. X    typedef unsigned short    ino_t;    /* (assuming original UFS) */
  61. X    typedef long        off_t;    /* long is forced by lseek() */
  62. X
  63. X    None of this should be necessary for any modern UNIX system.
  64. X
  65. X1)  Copy the file dirent.h to /usr/include/dirent.h and copy the file
  66. X    sys.dirent.h to /usr/include/sys/dirent.h.  (The file sys._dir.h is also
  67. X    provided for the BRL UNIX System V emulation for 4.nBSD.  That environment
  68. X    uses different directory names for everything.)
  69. X
  70. X2)  Copy the file directory.3c to /usr/man/man3/directory.3 and copy the file
  71. X    dirent.4 to /usr/man/man5/dirent.5; edit the new file
  72. X    /usr/man/man3/directory.3 to change the "SEE ALSO" reference from dirent(4)
  73. X    to dirent(5) and to change the 3C on the first line to 3; edit the new file
  74. X    /usr/man/man5/dirent.5 to change the 4 on the first line to 5; then print
  75. X    the manual pages via the command
  76. X
  77. X    man directory dirent
  78. X
  79. X    to see what the new routines are like.  (If you have a "catman" style of
  80. X    on-line manual, adapt these instructions accordingly.  Manual entries are
  81. X    kept in directories with other names on some systems such as UNIX System V.
  82. X    On systems that already had a directory library documented in some other
  83. X    manual entry, remove the superseded manual entry; if the description of the
  84. X    native filesystem directory format found by "man dir" refers to a directory
  85. X    library, modify it to simply refer to the entry for "dirent".)
  86. X
  87. X3)  Copy the files closedir.c, opendir.c, readdir.c, rewinddir.c, seekdir.c,
  88. X    and telldir.c to the "gen" or "port/gen" subdirectory of your C library
  89. X    source directory.  If you do not have a getdents() system call, copy the
  90. X    file getdents.c to the "sys" or "port/sys" subdirectory and copy the file
  91. X    getdents.2 to /usr/man/man2/getdents.2 (actually you may prefer to put this
  92. X    file in section 3 and adjust the references in the other manual entries
  93. X    accordingly; also adjust the references to dirent(4) to be to dirent(5) if
  94. X    that's where the entry is).  Edit the C library makefile(s) to include the
  95. X    new object modules in the C library.  (See the comments at the beginning of
  96. X    getdents.c for symbols that must be defined to configure getdents.c.)  Then
  97. X    remake and reinstall the C library.  Alternatively, you can just compile
  98. X    the new sources and insert their objects near the front of the C library
  99. X    /lib/libc.a using the "ar" utility (seekdir.o should precede readdir.o,
  100. X    which in turn should precede getdents.o).  On some systems you then need to
  101. X    use the "ranlib" utility to update the archive symbol table.
  102. X
  103. X4)  After the C library has been updated, delete /usr/include/ndir.h or any
  104. X    other header used with a previous directory library to prevent inadvertent
  105. X    use of the superseded directory access interface.  Also delete any
  106. X    corresponding library such as /usr/lib/libndir.a.
  107. X
  108. X5)  To verify installation, try compiling, linking, and running the program
  109. X    testdir.c.  This program searches the current directory "." for each file
  110. X    named as a program argument and prints `"FOO" found.' or `"FOO" not found.'
  111. X    where FOO is of course replaced by the name being sought in the directory.
  112. X    Try something like
  113. X
  114. X    cd /usr/bin            # a multi-block directory
  115. X    WHEREVER/testdir FOO lint BAR f77 XYZZY
  116. X
  117. X    which should produce the output
  118. X
  119. X    "FOO" not found.
  120. X    "lint" found.
  121. X    "BAR" not found.
  122. X    "f77" found.
  123. X    "XYZZY" not found.
  124. X
  125. X    A more thorough test would be
  126. X
  127. X    cd /usr/bin            # a multi-block directory
  128. X    WHEREVER/testdir `ls -a` | grep 'not found'
  129. X
  130. X    This program does not test the seekdir() and telldir() functions.
  131. X
  132. X6)  Notify your programmers that all directory access must be made through the
  133. X    new interface, and that documentation is available via
  134. X
  135. X    man directory dirent
  136. X
  137. X    Make the NOTES file available to those programmers who might want to
  138. X    understand what this is all about.
  139. X
  140. X7)  Change all system sources that were accessing directories to use the new
  141. X    routines.  Nearly all such sources contain the line
  142. X
  143. X    #include <sys/dir.h>
  144. X    or
  145. X    #include <ndir.h>
  146. X
  147. X    so they should be easy to find.  (If you earlier removed some other header
  148. X    file, that is, if this package superseded an earlier version of the
  149. X    directory access library, look for its name too.  See the conversion
  150. X    instructions in the NOTES file.)
  151. END_OF_INSTALL
  152. if test 5490 -ne `wc -c <INSTALL`; then
  153.     echo shar: \"INSTALL\" unpacked with wrong size!?
  154. fi
  155. # end of overwriting check
  156. fi
  157. echo shar: Extracting \"NOTES\" \(5314 characters\)
  158. if test -f NOTES ; then 
  159.   echo shar: Will not over-write existing file \"NOTES\"
  160. else
  161. sed "s/^X//" >NOTES <<'END_OF_NOTES'
  162. X
  163. X
  164. XNOTES FOR NEARLY-POSIX-COMPATIBLE C LIBRARY DIRECTORY-ACCESS ROUTINES
  165. X
  166. X
  167. XOlder UNIX C libraries lacked support for reading directories, so historically
  168. Xprograms had knowledge of UNIX directory structure hard-coded into them.  When
  169. XBerkeley changed the format of directories for 4.2BSD, it became necessary to
  170. Xchange programs to work with the new structure.  Fortunately, Berkeley designed
  171. Xa small set of directory access routines to encapsulate knowledge of the new
  172. Xdirectory format so that user programs could deal with directory entries as an
  173. Xabstract data type.  (Unfortunately, they didn't get it quite right.)  The
  174. Xinterface to these routines was nearly independent of the particular
  175. Ximplementation of directories on any given UNIX system; this has become a
  176. Xparticularly important requirement with the advent of heterogeneous network
  177. Xfilesystems such as NFS.
  178. X
  179. XIt has consequently become possible to write portable applications that search
  180. Xdirectories by restricting all directory access to use these new interface
  181. Xroutines.  The sources supplied here are a total rewrite of Berkeley's code,
  182. Xincorporating ideas from a variety of sources and conforming as closely to
  183. Xpublished standards as possible, and are in the PUBLIC DOMAIN to encourage
  184. Xtheir widespread adoption.  They support four methods of access to system
  185. Xdirectories: the original UNIX filesystem via read(), the 4.2BSD filesystem via
  186. Xread(), NFS and native filesystems via getdirentries(), and SVR3 getdents().
  187. XThe other three types are accomplished by appropriate emulation of the SVR3
  188. Xgetdents() system call, which attains portability at the cost of slightly more
  189. Xdata movement than absolutely necessary for some systems.  These routines
  190. Xshould be added to the standard C library on all UNIX systems, and all existing
  191. Xand future applications should be changed to use this interface.  Once this is
  192. Xdone, there should be no portability problems due to differences in underlying
  193. Xdirectory structures among UNIX systems.  (When porting your applications to
  194. Xother UNIX systems, you can always carry this package around with you.)
  195. X
  196. XAn additional benefit of these routines is that they buffer directory input,
  197. Xwhich provides improved access speed over raw read()s of one entry at a time.
  198. X
  199. XOne annoying compatibility problem has arisen along the way, namely that the
  200. Xoriginal Berkeley interface used the same name, struct direct, for the new data
  201. Xstructure as had been used for the original UNIX filesystem directory record
  202. Xstructure.  This name was changed by the IEEE 1003.1 (POSIX) Working Group to
  203. X"struct dirent" and was picked up for SVR3 under the new name; it is also the
  204. Xname used in this portable package.  I believe it is necessary to bite the
  205. Xbullet and adopt the new non-conflicting name.  Code using a 4.2BSD-compatible
  206. Xpackage needs to be slightly revised to work with this new package, as follows:
  207. X    Change
  208. X        #include <ndir.h>    /* Ninth Edition UNIX */
  209. X    or
  210. X        #include <sys/dir.h>    /* 4.2BSD */
  211. X    or
  212. X        #include <dir.h>    /* BRL System V emulation */
  213. X    to
  214. X        #include <sys/types.h>    /* if not already #included */
  215. X        #include <dirent.h>
  216. X
  217. X    Change
  218. X        struct direct
  219. X    to
  220. X        struct dirent
  221. X
  222. X    Change
  223. X        (anything)->d_namlen
  224. X    to
  225. X        strlen( (anything)->d_name )
  226. X
  227. XThere is a minor compatibility problem in that the closedir() function was
  228. Xoriginally defined to have type void, but IEEE 1003.1 changed this to type int,
  229. Xwhich is what this implementation supports (even though I disagree with the
  230. Xchange).  However, the difference does not affect most applications.
  231. X
  232. XAnother minor problem is that IEEE 1003.1 defined the d_name member of a struct
  233. Xdirent to be an array of maximum length; this does not permit use of compact
  234. Xvariable-length entries directly from a directory block buffer.  This part of
  235. Xthe specification is incompatible with efficient use of the getdents() system
  236. Xcall, and I have therefore chosen to follow the SVID specification instead of
  237. XIEEE 1003.1 (which I hope is changed for the final-use standard).  This
  238. Xdeviation should have little or no impact on sensibly-coded applications, since
  239. Xthe relevant d_name length is that given by strlen(), not the declared array
  240. Xsize.
  241. X
  242. XError handling is not completely satisfactory, due to the variety of possible
  243. Xfailure modes in a general setting.  For example, the rewinddir() function
  244. Xmight fail, but there is no good way to indicate this.  I have tried to
  245. Xfollow the specifications in IEEE 1003.1 and the SVID as closely as possible,
  246. Xbut there are minor deviations in this regard.  Applications should not rely
  247. Xtoo heavily on exact failure mode semantics.
  248. X
  249. XPlease do not change the new standard interface in any way, as that would
  250. Xdefeat the major purpose of this package!  (It's okay to alter the internal
  251. Ximplementation if you really have to, although I tried to make this unnecessary
  252. Xfor the vast majority of UNIX variants.)
  253. X
  254. XInstallation instructions can be found in the file named INSTALL.
  255. X
  256. XThis implementation is provided by:
  257. X
  258. X    Douglas A. Gwyn
  259. X    U.S. Army Ballistic Research Laboratory
  260. X    SLCBR-VL-V
  261. X    Aberdeen Proving Ground, MD 21005-5066
  262. X
  263. X    (301)278-6647
  264. X
  265. X    Gwyn@BRL.MIL or seismo!brl!gwyn
  266. X
  267. XThis is UNSUPPORTED, use-at-your-own-risk, free software in the public domain.
  268. XHowever, I would appreciate hearing of any actual bugs you find in this
  269. Ximplementation and/or any improvements you come up with.
  270. END_OF_NOTES
  271. if test 5314 -ne `wc -c <NOTES`; then
  272.     echo shar: \"NOTES\" unpacked with wrong size!?
  273. fi
  274. # end of overwriting check
  275. fi
  276. echo shar: Extracting \"closedir.c\" \(568 characters\)
  277. if test -f closedir.c ; then 
  278.   echo shar: Will not over-write existing file \"closedir.c\"
  279. else
  280. sed "s/^X//" >closedir.c <<'END_OF_closedir.c'
  281. X/*
  282. X    closedir -- close a directory stream
  283. X
  284. X    last edit:    25-Apr-1987    D A Gwyn
  285. X*/
  286. X
  287. X#include    <sys/errno.h>
  288. X#include    <sys/types.h>
  289. X#include    <dirent.h>
  290. X
  291. Xtypedef char    *pointer;        /* (void *) if you have it */
  292. X
  293. Xextern void    free();
  294. Xextern int    close();
  295. X
  296. Xextern int    errno;
  297. X
  298. X#ifndef NULL
  299. X#define    NULL    0
  300. X#endif
  301. X
  302. Xint
  303. Xclosedir( dirp )
  304. X    register DIR    *dirp;        /* stream from opendir() */
  305. X    {
  306. X    if ( dirp == NULL || dirp->dd_buf == NULL )
  307. X        {
  308. X        errno = EFAULT;
  309. X        return -1;        /* invalid pointer */
  310. X        }
  311. X
  312. X    free( (pointer)dirp->dd_buf );
  313. X    free( (pointer)dirp );
  314. X    return close( dirp->dd_fd );
  315. X    }
  316. END_OF_closedir.c
  317. if test 568 -ne `wc -c <closedir.c`; then
  318.     echo shar: \"closedir.c\" unpacked with wrong size!?
  319. fi
  320. # end of overwriting check
  321. fi
  322. echo shar: Extracting \"directory.3c\" \(4136 characters\)
  323. if test -f directory.3c ; then 
  324.   echo shar: Will not over-write existing file \"directory.3c\"
  325. else
  326. sed "s/^X//" >directory.3c <<'END_OF_directory.3c'
  327. X.TH DIRECTORY 3C "Standard Extension"
  328. X.SH NAME
  329. Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- directory operations
  330. X.SH SYNOPSIS
  331. X.B "#include <sys/types.h>"
  332. X.br
  333. X.B "#include <dirent.h>"
  334. X.P
  335. X.B "DIR \(**opendir (dirname)"
  336. X.br
  337. X.B "char \(**dirname;"
  338. X.P
  339. X.B "struct dirent \(**readdir (dirp)"
  340. X.br
  341. X.B "DIR \(**dirp;"
  342. X.P
  343. X.B "off_t telldir (dirp)"
  344. X.br
  345. X.B "DIR \(**dirp;"
  346. X.P
  347. X.B "void seekdir (dirp, loc)"
  348. X.br
  349. X.B "DIR \(**dirp;"
  350. X.br
  351. X.B "off_t loc;"
  352. X.P
  353. X.B "void rewinddir (dirp)"
  354. X.br
  355. X.B "DIR \(**dirp;"
  356. X.P
  357. X.B "int closedir (dirp)"
  358. X.br
  359. X.B "DIR \(**dirp;"
  360. X.SH DESCRIPTION
  361. X.I Opendir
  362. Xestablishes a connection between
  363. Xthe directory named by
  364. X.I dirname
  365. Xand a unique object of type
  366. X.SM DIR
  367. Xknown as a
  368. X.I "directory stream"
  369. Xthat it creates.
  370. X.I Opendir
  371. Xreturns a pointer to be used to identify the
  372. Xdirectory stream
  373. Xin subsequent operations.
  374. XA
  375. X.SM NULL
  376. Xpointer is returned if
  377. X.I dirname
  378. Xcannot be accessed or is not a directory,
  379. Xor if
  380. X.I opendir
  381. Xis unable to create the
  382. X.SM DIR
  383. Xobject
  384. X(perhaps due to insufficient memory).
  385. X.P
  386. X.I Readdir
  387. Xreturns a pointer to an internal structure
  388. Xcontaining information about the next active directory entry.
  389. XNo inactive entries are reported.
  390. XThe internal structure may be overwritten by
  391. Xanother operation on the same
  392. Xdirectory stream;
  393. Xthe amount of storage needed to hold a copy
  394. Xof the internal structure is given by the value of a macro,
  395. X.IR DIRENTSIZ(strlen(direntp\->d_name)) ,
  396. Xnot by
  397. X.I "sizeof(struct\ dirent)"
  398. Xas one might expect.
  399. XA
  400. X.SM NULL
  401. Xpointer is returned
  402. Xupon reaching the end of the directory,
  403. Xupon detecting an invalid location in the directory,
  404. Xor upon occurrence of an error while reading the directory.
  405. X.P
  406. X.I Telldir
  407. Xreturns the current position associated with the named
  408. Xdirectory stream
  409. Xfor later use as an argument to
  410. X.IR seekdir .
  411. X.P
  412. X.I Seekdir
  413. Xsets the position of the next
  414. X.I readdir
  415. Xoperation on the named
  416. Xdirectory stream.
  417. XThe new position reverts to the one associated with the
  418. Xdirectory stream
  419. Xwhen the
  420. X.I telldir
  421. Xoperation from which
  422. X.I loc
  423. Xwas obtained was performed.
  424. X.P
  425. X.I Rewinddir
  426. Xresets the position of the named
  427. Xdirectory stream
  428. Xto the beginning of the directory.
  429. XAll buffered data for the directory stream is discarded,
  430. Xthereby guaranteeing that the actual
  431. Xfile system directory will be referred to for the next
  432. X.I readdir
  433. Xon the
  434. Xdirectory stream.
  435. X.P
  436. X.I Closedir
  437. Xcloses the named
  438. Xdirectory stream;
  439. Xinternal resources used for the
  440. Xdirectory stream are liberated,
  441. Xand subsequent use of the associated
  442. X.SM DIR
  443. Xobject is no longer valid.
  444. X.I Closedir
  445. Xreturns a value of zero if no error occurs,
  446. X\-1 otherwise.
  447. X.P
  448. XThere are several possible errors that can occur
  449. Xas a result of these operations;
  450. Xthe external integer variable
  451. X.I errno
  452. Xis set to indicate the specific error.
  453. X.RI ( Readdir 's
  454. Xdetection of the normal end of a directory
  455. Xis not considered to be an error.)
  456. X.SH EXAMPLE
  457. XSample code which searches the current working directory for entry
  458. X.IR name :
  459. X.P
  460. X.ft B
  461. X    dirp = opendir( "." );
  462. X.br
  463. X    while ( (dp = readdir( dirp )) != NULL )
  464. X.br
  465. X        if ( strcmp( dp\->d_name, name ) == 0 )
  466. X.br
  467. X            {
  468. X.br
  469. X            (void) closedir( dirp );
  470. X.br
  471. X            return FOUND;
  472. X.br
  473. X            }
  474. X.br
  475. X    (void) closedir( dirp );
  476. X.br
  477. X    return NOT_FOUND;
  478. X.ft P
  479. X.SH "SEE ALSO"
  480. Xgetdents(2), dirent(4).
  481. X.SH WARNINGS
  482. XEntries for "." and ".."
  483. Xmay not be reported for some file system types.
  484. X.P
  485. XThe value returned by
  486. X.I telldir
  487. Xneed not have any simple interpretation
  488. Xand should only be used as an argument to
  489. X.IR seekdir .
  490. XSimilarly,
  491. Xthe
  492. X.I loc
  493. Xargument to
  494. X.I seekdir
  495. Xmust be obtained from a previous
  496. X.I telldir
  497. Xoperation on the same
  498. Xdirectory stream.
  499. X.P
  500. X.I Telldir
  501. Xand
  502. X.I seekdir
  503. Xare unreliable when used in conjunction with
  504. Xfile systems that perform directory compaction or expansion
  505. Xor when the directory stream has been closed and reopened.
  506. XIt is best to avoid using
  507. X.I telldir
  508. Xand
  509. X.I seekdir
  510. Xaltogether.
  511. X.P
  512. XThe exact set of
  513. X.I errno
  514. Xvalues and meanings may vary among implementations.
  515. X.P
  516. XBecause directory entries can dynamically
  517. Xappear and disappear,
  518. Xand because directory contents are buffered
  519. Xby these routines,
  520. Xan application may need to continually rescan
  521. Xa directory to maintain an accurate picture
  522. Xof its active entries.
  523. END_OF_directory.3c
  524. if test 4136 -ne `wc -c <directory.3c`; then
  525.     echo shar: \"directory.3c\" unpacked with wrong size!?
  526. fi
  527. # end of overwriting check
  528. fi
  529. echo shar: Extracting \"dirent.4\" \(1593 characters\)
  530. if test -f dirent.4 ; then 
  531.   echo shar: Will not over-write existing file \"dirent.4\"
  532. else
  533. sed "s/^X//" >dirent.4 <<'END_OF_dirent.4'
  534. X.TH DIRENT 4 "Standard Extension"
  535. X.SH NAME
  536. Xdirent \- file system independent directory entry
  537. X.SH SYNOPSIS
  538. X.B "#include <sys/types.h>"
  539. X.br
  540. X.B "#include <sys/dirent.h>"
  541. X.SH DESCRIPTION
  542. XDifferent file system types
  543. Xmay have different directory entries.
  544. XThe
  545. X.I dirent
  546. Xstructure defines a
  547. Xfile system independent directory entry,
  548. Xwhich contains information common to
  549. Xdirectory entries in different file system types.
  550. XA set of these structures is returned by the
  551. X.IR getdents (2)
  552. Xsystem call.
  553. X.P
  554. XThe
  555. X.I dirent
  556. Xstructure is defined below.
  557. X.br
  558. Xstruct    dirent    {
  559. X.br
  560. X            long            d_ino;
  561. X.br
  562. X            off_t            d_off;
  563. X.br
  564. X            unsigned short        d_reclen;
  565. X.br
  566. X            char            d_name[1];
  567. X.br
  568. X        };
  569. X.P
  570. XThe field
  571. X.I d_ino
  572. Xis a number which is unique
  573. Xfor each file in the file system.
  574. XThe field
  575. X.I d_off\^
  576. Xrepresents an offset of that directory entry
  577. Xin the actual file system directory.
  578. XThe field
  579. X.I d_name
  580. Xis the beginning of the character array
  581. Xgiving the name of the directory entry.
  582. XThis name is null terminated
  583. Xand may have at most
  584. X.SM NAME_MAX
  585. Xcharacters in addition to the null terminator.
  586. XThis results in file system independent directory entries
  587. Xbeing variable-length entities.
  588. XThe value of
  589. X.I d_reclen
  590. Xis the record length of this entry.
  591. XThis length is defined to be the number of bytes
  592. Xbetween the beginning of the current entry and the next one,
  593. Xadjusted so that the next entry
  594. Xwill start on a long boundary.
  595. X.SH FILES
  596. X/usr/include/sys/dirent.h
  597. X.SH "SEE ALSO"
  598. Xgetdents(2).
  599. X.SH WARNING
  600. XThe field
  601. X.I d_off\^
  602. Xdoes not have a simple interpretation
  603. Xfor some file system types
  604. Xand should not be used directly by applications.
  605. END_OF_dirent.4
  606. if test 1593 -ne `wc -c <dirent.4`; then
  607.     echo shar: \"dirent.4\" unpacked with wrong size!?
  608. fi
  609. # end of overwriting check
  610. fi
  611. echo shar: Extracting \"dirent.h\" \(730 characters\)
  612. if test -f dirent.h ; then 
  613.   echo shar: Will not over-write existing file \"dirent.h\"
  614. else
  615. sed "s/^X//" >dirent.h <<'END_OF_dirent.h'
  616. X/*
  617. X    <dirent.h> -- definitions for SVR3 directory access routines
  618. X
  619. X    last edit:    25-Apr-1987    D A Gwyn
  620. X
  621. X    Prerequisite:    <sys/types.h>
  622. X*/
  623. X
  624. X#include    <sys/dirent.h>
  625. X
  626. X#define    DIRBUF        8192        /* buffer size for fs-indep. dirs */
  627. X    /* must in general be larger than the filesystem buffer size */
  628. X
  629. Xtypedef struct
  630. X    {
  631. X    int    dd_fd;            /* file descriptor */
  632. X    int    dd_loc;            /* offset in block */
  633. X    int    dd_size;        /* amount of valid data */
  634. X    char    *dd_buf;        /* -> directory block */
  635. X    }    DIR;            /* stream data from opendir() */
  636. X
  637. Xextern DIR        *opendir();
  638. Xextern struct dirent    *readdir();
  639. Xextern off_t        telldir();
  640. Xextern void        seekdir();
  641. Xextern void        rewinddir();
  642. Xextern int        closedir();
  643. X
  644. X#ifndef NULL
  645. X#define    NULL    0            /* DAG -- added for convenience */
  646. X#endif
  647. END_OF_dirent.h
  648. if test 730 -ne `wc -c <dirent.h`; then
  649.     echo shar: \"dirent.h\" unpacked with wrong size!?
  650. fi
  651. # end of overwriting check
  652. fi
  653. echo shar: Extracting \"getdents.2\" \(1922 characters\)
  654. if test -f getdents.2 ; then 
  655.   echo shar: Will not over-write existing file \"getdents.2\"
  656. else
  657. sed "s/^X//" >getdents.2 <<'END_OF_getdents.2'
  658. X.TH GETDENTS 2 "Standard Extension"
  659. X.SH NAME
  660. Xgetdents \- get directory entries in a file system independent format
  661. X.SH SYNOPSIS
  662. X.B "#include <sys/types.h>"
  663. X.br
  664. X.B "#include <sys/dirent.h>"
  665. X.P
  666. X.B "int getdents (fildes, buf, nbyte)"
  667. X.br
  668. X.B "int fildes;"
  669. X.br
  670. X.B "char \(**buf;"
  671. X.br
  672. X.B "unsigned nbyte;"
  673. X.SH DESCRIPTION
  674. X.I Fildes
  675. Xis a file descriptor obtained from an
  676. X.IR open (2)
  677. Xor
  678. X.IR dup (2)
  679. Xsystem call.
  680. X.P
  681. X.I Getdents
  682. Xattempts to read
  683. X.I nbyte
  684. Xbytes from the directory associated with
  685. X.I fildes
  686. Xand to format them as
  687. Xfile system independent entries
  688. Xin the buffer pointed to by
  689. X.IR buf .
  690. XSince the file system independent directory entries
  691. Xare of variable length,
  692. Xin most cases the actual number of bytes returned
  693. Xwill be less than
  694. X.IR nbyte .
  695. X.P
  696. XThe file system independent directory entry is specified by the
  697. X.I dirent
  698. Xstructure.
  699. XFor a description of this see
  700. X.IR dirent (4).
  701. X.P
  702. XOn devices capable of seeking,
  703. X.I getdents
  704. Xstarts at a position in the file given by
  705. Xthe file pointer associated with
  706. X.IR fildes .
  707. XUpon return from
  708. X.IR getdents ,
  709. Xthe file pointer has been incremented
  710. Xto point to the next directory entry.
  711. X.P
  712. XThis system call was developed in order to implement the
  713. X.I readdir
  714. Xroutine
  715. X[for a description see
  716. X.IR directory (3C)]
  717. Xand should not be used for other purposes.
  718. X.SH "SEE ALSO"
  719. Xdirectory(3C), dirent(4).
  720. X.SH DIAGNOSTICS
  721. XUpon successful completion
  722. Xa non-negative integer is returned
  723. Xindicating the number of bytes of
  724. X.I buf\^
  725. Xactually filled.
  726. X(This need not be the number actually used
  727. Xin the actual directory file.)\|\|
  728. XA value of zero
  729. Xindicates the end of the directory has been reached.
  730. XIf
  731. X.I getdents
  732. Xfails for any other reason,
  733. Xa value of \-1 is returned and
  734. Xthe external integer variable
  735. X.I errno
  736. Xis set to indicate the error.
  737. X.SH WARNINGS
  738. XEntries for "." and ".."
  739. Xmay not be reported for some file system types.
  740. X.P
  741. XThe exact set of
  742. X.I errno
  743. Xvalues and meanings may vary among implementations.
  744. END_OF_getdents.2
  745. if test 1922 -ne `wc -c <getdents.2`; then
  746.     echo shar: \"getdents.2\" unpacked with wrong size!?
  747. fi
  748. # end of overwriting check
  749. fi
  750. echo shar: Extracting \"getdents.c\" \(6375 characters\)
  751. if test -f getdents.c ; then 
  752.   echo shar: Will not over-write existing file \"getdents.c\"
  753. else
  754. sed "s/^X//" >getdents.c <<'END_OF_getdents.c'
  755. X/*
  756. X    getdents -- get directory entries in a file system independent format
  757. X            (SVR3 system call emulation)
  758. X
  759. X    last edit:    25-Apr-1987    D A Gwyn
  760. X
  761. X    This single source file supports several different methods of
  762. X    getting directory entries from the operating system.  Define
  763. X    whichever one of the following describes your system:
  764. X
  765. X    UFS    original UNIX filesystem (14-character name limit)
  766. X    BFS    4.2BSD (also 4.3BSD) native filesystem (long names)
  767. X    NFS    getdirentries() system call
  768. X
  769. X    Also define any of the following that are pertinent:
  770. X
  771. X    BRL    BRL UNIX System V emulation environment on 4.nBSD
  772. X    UNK    have _getdents() system call, but kernel may not support it
  773. X
  774. X    If your C library has a getdents() system call interface, but you
  775. X    can't count on all kernels on which your application binaries may
  776. X    run to support it, change the system call interface name to
  777. X    _getdents() and define "UNK" to enable the system-call validity
  778. X    test in this "wrapper" around _getdents().
  779. X
  780. X    If your system has a getdents() system call that is guaranteed 
  781. X    to always work, you shouldn't be using this source file at all.
  782. X*/
  783. X
  784. X#include    <sys/errno.h>
  785. X#include    <sys/types.h>
  786. X#ifdef BRL
  787. X#include    <sys/_dir.h>        /* BSD flavor, not System V */
  788. X#else
  789. X#include    <sys/dir.h>
  790. X#undef    MAXNAMLEN            /* avoid conflict with SVR3 */
  791. X    /* Good thing we don't need to use the DIRSIZ() macro! */
  792. X#ifdef d_ino                /* 4.3BSD/NFS using d_fileno */
  793. X#undef    d_ino                /* (not absolutely necessary) */
  794. X#else
  795. X#define    d_fileno    d_ino        /* (struct direct) member */
  796. X#endif
  797. X#endif
  798. X#include    <sys/dirent.h>
  799. X#include    <sys/stat.h>
  800. X#ifdef UNK
  801. X#ifndef UFS
  802. X#include "***** ERROR ***** UNK applies only to UFS"
  803. X/* One could do something similar for getdirentries(), but I didn't bother. */
  804. X#endif
  805. X#include    <signal.h>
  806. X#endif
  807. X
  808. X#if defined(UFS) + defined(BFS) + defined(NFS) != 1    /* sanity check */
  809. X#include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
  810. X#endif
  811. X
  812. X#ifdef UFS
  813. X#define    RecLen( dp )    (sizeof(struct direct))    /* fixed-length entries */
  814. X#else    /* BFS || NFS */
  815. X#define    RecLen( dp )    ((dp)->d_reclen)    /* variable-length entries */
  816. X#endif
  817. X
  818. X#ifdef NFS
  819. X#ifdef BRL
  820. X#define    getdirentries    _getdirentries    /* package hides this system call */
  821. X#endif
  822. Xextern int    getdirentries();
  823. Xstatic long    dummy;            /* getdirentries() needs basep */
  824. X#define    GetBlock( fd, buf, n )    getdirentries( fd, buf, (unsigned)n, &dummy )
  825. X#else    /* UFS || BFS */
  826. X#ifdef BRL
  827. X#define read    _read            /* avoid emulation overhead */
  828. X#endif
  829. Xextern int    read();
  830. X#define    GetBlock( fd, buf, n )    read( fd, buf, (unsigned)n )
  831. X#endif
  832. X
  833. X#ifdef UNK
  834. Xextern int    _getdents();        /* actual system call */
  835. X#endif
  836. X
  837. Xextern char    *strncpy();
  838. Xextern int    fstat(), strlen();
  839. Xextern off_t    lseek();
  840. X
  841. Xextern int    errno;
  842. X
  843. X#ifndef DIRBLKSIZ
  844. X#define    DIRBLKSIZ    4096        /* directory file read buffer size */
  845. X#endif
  846. X
  847. X#ifndef NULL
  848. X#define    NULL    0
  849. X#endif
  850. X
  851. X#ifndef SEEK_CUR
  852. X#define    SEEK_CUR    1
  853. X#endif
  854. X
  855. X#ifndef S_ISDIR                /* macro to test for directory file */
  856. X#define    S_ISDIR( mode )        (((mode) & S_IFMT) == S_IFDIR)
  857. X#endif
  858. X
  859. X#ifdef UNK
  860. Xstatic enum    { maybe, no, yes }    state = maybe;
  861. X                    /* does _getdents() work? */
  862. X
  863. X/*ARGSUSED*/
  864. Xstatic void
  865. Xsig_catch( sig )
  866. X    int    sig;            /* must be SIGSYS */
  867. X    {
  868. X    state = no;            /* attempted _getdents() faulted */
  869. X    }
  870. X#endif
  871. X
  872. Xint
  873. Xgetdents( fildes, buf, nbyte )        /* returns # bytes read;
  874. X                       0 on EOF, -1 on error */
  875. X    int            fildes;    /* directory file descriptor */
  876. X    char            *buf;    /* where to put the (struct dirent)s */
  877. X    unsigned        nbyte;    /* size of buf[] */
  878. X    {
  879. X    int            serrno;    /* entry errno */
  880. X    off_t            offset;    /* initial directory file offset */
  881. X    struct stat        statb;    /* fstat() info */
  882. X    union    {
  883. X        char        dblk[DIRBLKSIZ];
  884. X                    /* directory file block buffer */
  885. X        struct direct    dummy;    /* just for alignment */
  886. X        }    u;        /* (avoids having to malloc()) */
  887. X    register struct direct    *dp;    /* -> u.dblk[.] */
  888. X    register struct dirent    *bp;    /* -> buf[.] */
  889. X
  890. X#ifdef UNK
  891. X    switch ( state )
  892. X        {
  893. X        void        (*shdlr)();    /* entry SIGSYS handler */
  894. X        register int    retval;    /* return from _getdents() if any */
  895. X
  896. X    case yes:            /* _getdents() is known to work */
  897. X        return _getdents( fildes, buf, nbyte );
  898. X
  899. X    case maybe:            /* first time only */
  900. X        shdlr = signal( SIGSYS, sig_catch );
  901. X        retval = _getdents( fildes, buf, nbyte );    /* try it */
  902. X        (void)signal( SIGSYS, shdlr );
  903. X
  904. X        if ( state == maybe )    /* SIGSYS did not occur */
  905. X            {
  906. X            state = yes;    /* so _getdents() must have worked */
  907. X            return retval;
  908. X            }
  909. X        /* else fall through into emulation */
  910. X
  911. X/*    case no:    /* fall through into emulation */
  912. X        }
  913. X#endif
  914. X
  915. X    if ( buf == NULL || (unsigned long)buf % sizeof(long) != 0 /* ugh */ )
  916. X        {
  917. X        errno = EFAULT;        /* invalid pointer */
  918. X        return -1;
  919. X        }
  920. X
  921. X    if ( fstat( fildes, &statb ) != 0 )
  922. X        return -1;        /* errno set by fstat() */
  923. X
  924. X    if ( !S_ISDIR( statb.st_mode ) )
  925. X        {
  926. X        errno = ENOTDIR;    /* not a directory */
  927. X        return -1;
  928. X        }
  929. X
  930. X    if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 )
  931. X        return -1;        /* errno set by lseek() */
  932. X
  933. X#ifdef BFS                /* no telling what remote hosts do */
  934. X    if ( (unsigned long)offset % DIRBLKSIZ != 0 )
  935. X        {
  936. X        errno = ENOENT;        /* file pointer probably misaligned */
  937. X        return -1;
  938. X        }
  939. X#endif
  940. X
  941. X    serrno = errno;            /* save entry errno */
  942. X
  943. X    for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; )
  944. X        {            /* convert next directory block */
  945. X        int    size;
  946. X
  947. X        do    size = GetBlock( fildes, u.dblk, DIRBLKSIZ );
  948. X        while ( size == -1 && errno == EINTR );
  949. X
  950. X        if ( size <= 0 )
  951. X            return size;    /* EOF or error (EBADF) */
  952. X
  953. X        for ( dp = (struct direct *)u.dblk;
  954. X              (char *)dp < &u.dblk[size];
  955. X              dp = (struct direct *)((char *)dp + RecLen( dp ))
  956. X            )    {
  957. X#ifndef UFS
  958. X            if ( dp->d_reclen <= 0 )
  959. X                {
  960. X                errno = EIO;    /* corrupted directory */
  961. X                return -1;
  962. X                }
  963. X#endif
  964. X
  965. X            if ( dp->d_fileno != 0 )
  966. X                {    /* non-empty; copy to user buffer */
  967. X                register int    reclen =
  968. X                    DIRENTSIZ( strlen( dp->d_name ) );
  969. X
  970. X                if ( (char *)bp + reclen > &buf[nbyte] )
  971. X                    {
  972. X                    errno = EINVAL;
  973. X                    return -1;    /* buf too small */
  974. X                    }
  975. X
  976. X                bp->d_ino = dp->d_fileno;
  977. X                bp->d_off = offset + ((char *)dp - u.dblk);
  978. X                bp->d_reclen = reclen;
  979. X                (void)strncpy( bp->d_name, dp->d_name,
  980. X                           reclen - DIRENTBASESIZ
  981. X                         );    /* adds NUL padding */
  982. X
  983. X                bp = (struct dirent *)((char *)bp + reclen);
  984. X                }
  985. X            }
  986. X
  987. X        if ( (char *)dp > &u.dblk[size] )
  988. X            {
  989. X            errno = EIO;    /* corrupted directory */
  990. X            return -1;
  991. X            }
  992. X        }
  993. X
  994. X    errno = serrno;            /* restore entry errno */
  995. X    return (char *)bp - buf;    /* return # bytes read */
  996. X    }
  997. END_OF_getdents.c
  998. if test 6375 -ne `wc -c <getdents.c`; then
  999.     echo shar: \"getdents.c\" unpacked with wrong size!?
  1000. fi
  1001. # end of overwriting check
  1002. fi
  1003. echo shar: Extracting \"opendir.c\" \(1468 characters\)
  1004. if test -f opendir.c ; then 
  1005.   echo shar: Will not over-write existing file \"opendir.c\"
  1006. else
  1007. sed "s/^X//" >opendir.c <<'END_OF_opendir.c'
  1008. X/*
  1009. X    opendir -- open a directory stream
  1010. X
  1011. X    last edit:    25-Apr-1987    D A Gwyn
  1012. X*/
  1013. X
  1014. X#include    <sys/errno.h>
  1015. X#include    <sys/types.h>
  1016. X#include    <sys/stat.h>
  1017. X#include    <dirent.h>
  1018. X
  1019. X#ifdef BRL
  1020. X#define open    _open            /* avoid emulation overhead */
  1021. X#endif
  1022. X
  1023. Xtypedef char    *pointer;        /* (void *) if you have it */
  1024. X
  1025. Xextern void    free();
  1026. Xextern pointer    malloc();
  1027. Xextern int    open(), close(), fstat();
  1028. X
  1029. Xextern int    errno;
  1030. X
  1031. X#ifndef NULL
  1032. X#define    NULL    0
  1033. X#endif
  1034. X
  1035. X#ifndef O_RDONLY
  1036. X#define    O_RDONLY    0
  1037. X#endif
  1038. X
  1039. X#ifndef S_ISDIR                /* macro to test for directory file */
  1040. X#define    S_ISDIR( mode )        (((mode) & S_IFMT) == S_IFDIR)
  1041. X#endif
  1042. X
  1043. XDIR *
  1044. Xopendir( dirname )
  1045. X    char        *dirname;    /* name of directory */
  1046. X    {
  1047. X    register DIR    *dirp;        /* -> malloc'ed storage */
  1048. X    register int    fd;        /* file descriptor for read */
  1049. X    struct stat    sbuf;        /* result of fstat() */
  1050. X
  1051. X    if ( (fd = open( dirname, O_RDONLY )) < 0 )
  1052. X        return NULL;        /* errno set by open() */
  1053. X
  1054. X    if ( fstat( fd, &sbuf ) != 0 || !S_ISDIR( sbuf.st_mode ) )
  1055. X        {
  1056. X        (void)close( fd );
  1057. X        errno = ENOTDIR;
  1058. X        return NULL;        /* not a directory */
  1059. X        }
  1060. X
  1061. X    if ( (dirp = (DIR *)malloc( sizeof(DIR) )) == NULL
  1062. X      || (dirp->dd_buf = (char *)malloc( (unsigned)DIRBUF )) == NULL
  1063. X       )    {
  1064. X        register int    serrno = errno;
  1065. X                    /* errno set to ENOMEM by sbrk() */
  1066. X
  1067. X        if ( dirp != NULL )
  1068. X            free( (pointer)dirp );
  1069. X
  1070. X        (void)close( fd );
  1071. X        errno = serrno;
  1072. X        return NULL;        /* not enough memory */
  1073. X        }
  1074. X
  1075. X    dirp->dd_fd = fd;
  1076. X    dirp->dd_loc = dirp->dd_size = 0;    /* refill needed */
  1077. X
  1078. X    return dirp;
  1079. X    }
  1080. END_OF_opendir.c
  1081. if test 1468 -ne `wc -c <opendir.c`; then
  1082.     echo shar: \"opendir.c\" unpacked with wrong size!?
  1083. fi
  1084. # end of overwriting check
  1085. fi
  1086. echo shar: Extracting \"readdir.c\" \(991 characters\)
  1087. if test -f readdir.c ; then 
  1088.   echo shar: Will not over-write existing file \"readdir.c\"
  1089. else
  1090. sed "s/^X//" >readdir.c <<'END_OF_readdir.c'
  1091. X/*
  1092. X    readdir -- read next entry from a directory stream
  1093. X
  1094. X    last edit:    25-Apr-1987    D A Gwyn
  1095. X*/
  1096. X
  1097. X#include    <sys/errno.h>
  1098. X#include    <sys/types.h>
  1099. X#include    <dirent.h>
  1100. X
  1101. Xextern int    getdents();        /* SVR3 system call, or emulation */
  1102. X
  1103. Xextern int    errno;
  1104. X
  1105. X#ifndef NULL
  1106. X#define    NULL    0
  1107. X#endif
  1108. X
  1109. Xstruct dirent *
  1110. Xreaddir( dirp )
  1111. X    register DIR        *dirp;    /* stream from opendir() */
  1112. X    {
  1113. X    register struct dirent    *dp;    /* -> directory data */
  1114. X
  1115. X    if ( dirp == NULL || dirp->dd_buf == NULL )
  1116. X        {
  1117. X        errno = EFAULT;
  1118. X        return NULL;        /* invalid pointer */
  1119. X        }
  1120. X
  1121. X    do    {
  1122. X        if ( dirp->dd_loc >= dirp->dd_size )    /* empty or obsolete */
  1123. X            dirp->dd_loc = dirp->dd_size = 0;
  1124. X
  1125. X        if ( dirp->dd_size == 0    /* need to refill buffer */
  1126. X          && (dirp->dd_size =
  1127. X            getdents( dirp->dd_fd, dirp->dd_buf, (unsigned)DIRBUF )
  1128. X             ) <= 0
  1129. X           )
  1130. X            return NULL;    /* EOF or error */
  1131. X
  1132. X        dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc];
  1133. X        dirp->dd_loc += dp->d_reclen;
  1134. X        }
  1135. X    while ( dp->d_ino == 0L );    /* don't rely on getdents() */
  1136. X
  1137. X    return dp;
  1138. X    }
  1139. END_OF_readdir.c
  1140. if test 991 -ne `wc -c <readdir.c`; then
  1141.     echo shar: \"readdir.c\" unpacked with wrong size!?
  1142. fi
  1143. # end of overwriting check
  1144. fi
  1145. echo shar: Extracting \"rewinddir.c\" \(746 characters\)
  1146. if test -f rewinddir.c ; then 
  1147.   echo shar: Will not over-write existing file \"rewinddir.c\"
  1148. else
  1149. sed "s/^X//" >rewinddir.c <<'END_OF_rewinddir.c'
  1150. X/*
  1151. X    rewinddir -- rewind a directory stream
  1152. X
  1153. X    last edit:    25-Apr-1987    D A Gwyn
  1154. X
  1155. X    This is not simply a call to seekdir(), because seekdir()
  1156. X    will use the current buffer whenever possible and we need
  1157. X    rewinddir() to forget about buffered data.
  1158. X*/
  1159. X
  1160. X#include    <sys/errno.h>
  1161. X#include    <sys/types.h>
  1162. X#include    <dirent.h>
  1163. X
  1164. Xextern off_t    lseek();
  1165. X
  1166. Xextern int    errno;
  1167. X
  1168. X#ifndef NULL
  1169. X#define    NULL    0
  1170. X#endif
  1171. X
  1172. X#ifndef SEEK_SET
  1173. X#define    SEEK_SET    0
  1174. X#endif
  1175. X
  1176. Xvoid
  1177. Xrewinddir( dirp )
  1178. X    register DIR        *dirp;    /* stream from opendir() */
  1179. X    {
  1180. X    if ( dirp == NULL || dirp->dd_buf == NULL )
  1181. X        {
  1182. X        errno = EFAULT;
  1183. X        return;            /* invalid pointer */
  1184. X        }
  1185. X
  1186. X    dirp->dd_loc = dirp->dd_size = 0;    /* invalidate buffer */
  1187. X    (void)lseek( dirp->dd_fd, (off_t)0, SEEK_SET );    /* may set errno */
  1188. X    }
  1189. END_OF_rewinddir.c
  1190. if test 746 -ne `wc -c <rewinddir.c`; then
  1191.     echo shar: \"rewinddir.c\" unpacked with wrong size!?
  1192. fi
  1193. # end of overwriting check
  1194. fi
  1195. echo shar: Extracting \"seekdir.c\" \(2981 characters\)
  1196. if test -f seekdir.c ; then 
  1197.   echo shar: Will not over-write existing file \"seekdir.c\"
  1198. else
  1199. sed "s/^X//" >seekdir.c <<'END_OF_seekdir.c'
  1200. X/*
  1201. X    seekdir -- reposition a directory stream
  1202. X
  1203. X    last edit:    25-Apr-1987    D A Gwyn
  1204. X
  1205. X    An unsuccessful seekdir() will in general alter the current
  1206. X    directory position; beware.
  1207. X
  1208. X    NOTE:    4.nBSD directory compaction makes seekdir() & telldir()
  1209. X        practically impossible to do right.  Avoid using them!
  1210. X*/
  1211. X
  1212. X#include    <sys/errno.h>
  1213. X#include    <sys/types.h>
  1214. X#include    <dirent.h>
  1215. X
  1216. Xextern off_t    lseek();
  1217. X
  1218. Xextern int    errno;
  1219. X
  1220. X#ifndef NULL
  1221. X#define    NULL    0
  1222. X#endif
  1223. X
  1224. X#ifndef SEEK_SET
  1225. X#define    SEEK_SET    0
  1226. X#endif
  1227. X
  1228. Xtypedef int    bool;            /* Boolean data type */
  1229. X#define    false    0
  1230. X#define    true    1
  1231. X
  1232. Xvoid
  1233. Xseekdir( dirp, loc )
  1234. X    register DIR        *dirp;    /* stream from opendir() */
  1235. X    register off_t        loc;    /* position from telldir() */
  1236. X    {
  1237. X    register bool        rewind;    /* "start over when stymied" flag */
  1238. X
  1239. X    if ( dirp == NULL || dirp->dd_buf == NULL )
  1240. X        {
  1241. X        errno = EFAULT;
  1242. X        return;            /* invalid pointer */
  1243. X        }
  1244. X
  1245. X    /* A (struct dirent)'s d_off is an invented quantity on 4.nBSD
  1246. X       NFS-supporting systems, so it is not safe to lseek() to it. */
  1247. X
  1248. X    /* Monotonicity of d_off is heavily exploited in the following. */
  1249. X
  1250. X    /* This algorithm is tuned for modest directory sizes.  For
  1251. X       huge directories, it might be more efficient to read blocks
  1252. X       until the first d_off is too large, then back up one block,
  1253. X       or even to use binary search on the directory blocks.  I
  1254. X       doubt that the extra code for that would be worthwhile. */
  1255. X
  1256. X    if ( dirp->dd_loc >= dirp->dd_size    /* invalid index */
  1257. X      || ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off > loc
  1258. X                    /* too far along in buffer */
  1259. X       )
  1260. X        dirp->dd_loc = 0;    /* reset to beginning of buffer */
  1261. X    /* else save time by starting at current dirp->dd_loc */
  1262. X
  1263. X    for ( rewind = true; ; )
  1264. X        {
  1265. X        register struct dirent    *dp;
  1266. X
  1267. X        /* See whether the matching entry is in the current buffer. */
  1268. X
  1269. X        if ( (dirp->dd_loc < dirp->dd_size    /* valid index */
  1270. X           || readdir( dirp ) != NULL    /* next buffer read */
  1271. X           && (dirp->dd_loc = 0, true)    /* beginning of buffer set */
  1272. X             )
  1273. X          && (dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off
  1274. X            <= loc        /* match possible in this buffer */
  1275. X           )    {
  1276. X            for ( /* dp initialized above */ ;
  1277. X                  (char *)dp < &dirp->dd_buf[dirp->dd_size];
  1278. X                  dp = (struct dirent *)((char *)dp + dp->d_reclen)
  1279. X                )
  1280. X                if ( dp->d_off == loc )
  1281. X                    {    /* found it! */
  1282. X                    dirp->dd_loc =
  1283. X                        (char *)dp - dirp->dd_buf;
  1284. X                    return;
  1285. X                    }
  1286. X
  1287. X            rewind = false;    /* no point in backing up later */
  1288. X            dirp->dd_loc = dirp->dd_size;    /* set end of buffer */
  1289. X            }
  1290. X        else            /* whole buffer past matching entry */
  1291. X            if ( !rewind )
  1292. X                {    /* no point in searching further */
  1293. X                errno = EINVAL;
  1294. X                return;    /* no entry at specified loc */
  1295. X                }
  1296. X            else    {    /* rewind directory and start over */
  1297. X                rewind = false;    /* but only once! */
  1298. X
  1299. X                dirp->dd_loc = dirp->dd_size = 0;
  1300. X
  1301. X                if ( lseek( dirp->dd_fd, (off_t)0, SEEK_SET )
  1302. X                    != 0
  1303. X                   )
  1304. X                    return;    /* errno already set (EBADF) */
  1305. X
  1306. X                if ( loc == 0 )
  1307. X                    return; /* save time for rewinddir() */
  1308. X                }
  1309. X        }
  1310. X    }
  1311. END_OF_seekdir.c
  1312. if test 2981 -ne `wc -c <seekdir.c`; then
  1313.     echo shar: \"seekdir.c\" unpacked with wrong size!?
  1314. fi
  1315. # end of overwriting check
  1316. fi
  1317. echo shar: Extracting \"sys._dir.h\" \(2977 characters\)
  1318. if test -f sys._dir.h ; then 
  1319.   echo shar: Will not over-write existing file \"sys._dir.h\"
  1320. else
  1321. sed "s/^X//" >sys._dir.h <<'END_OF_sys._dir.h'
  1322. X/*
  1323. X    <sys/_dir.h> -- definitions for 4.2,4.3BSD directories
  1324. X
  1325. X    last edit:    25-Apr-1987    D A Gwyn
  1326. X
  1327. X    A directory consists of some number of blocks of DIRBLKSIZ bytes each,
  1328. X    where DIRBLKSIZ is chosen such that it can be transferred to disk in a
  1329. X    single atomic operation (e.g., 512 bytes on most machines).
  1330. X
  1331. X    Each DIRBLKSIZ-byte block contains some number of directory entry
  1332. X    structures, which are of variable length.  Each directory entry has the
  1333. X    beginning of a (struct direct) at the front of it, containing its
  1334. X    filesystem-unique ident number, the length of the entry, and the length
  1335. X    of the name contained in the entry.  These are followed by the NUL-
  1336. X    terminated name padded to a (long) boundary with 0 bytes.  The maximum
  1337. X    length of a name in a directory is MAXNAMELEN.
  1338. X
  1339. X    The macro DIRSIZ(dp) gives the amount of space required to represent a
  1340. X    directory entry.  Free space in a directory is represented by entries
  1341. X    that have dp->d_reclen > DIRSIZ(dp).  All DIRBLKSIZ bytes in a
  1342. X    directory block are claimed by the directory entries; this usually
  1343. X    results in the last entry in a directory having a large dp->d_reclen.
  1344. X    When entries are deleted from a directory, the space is returned to the
  1345. X    previous entry in the same directory block by increasing its
  1346. X    dp->d_reclen.  If the first entry of a directory block is free, then
  1347. X    its dp->d_fileno is set to 0; entries other than the first in a
  1348. X    directory do not normally have     dp->d_fileno set to 0.
  1349. X
  1350. X    prerequisite:    <sys/types.h>
  1351. X*/
  1352. X
  1353. X#if defined(accel) || defined(sun) || defined(vax)
  1354. X#define    DIRBLKSIZ    512        /* size of directory block */
  1355. X#else
  1356. X#ifdef alliant
  1357. X#define    DIRBLKSIZ    4096        /* size of directory block */
  1358. X#else
  1359. X#ifdef gould
  1360. X#define    DIRBLKSIZ    1024        /* size of directory block */
  1361. X#else
  1362. X#ifdef ns32000    /* Dynix System V */
  1363. X#define    DIRBLKSIZ    2600        /* size of directory block */
  1364. X#else    /* be conservative; multiple blocks are okay but fractions are not */
  1365. X#define    DIRBLKSIZ    4096        /* size of directory block */
  1366. X#endif
  1367. X#endif
  1368. X#endif
  1369. X#endif
  1370. X
  1371. X#define    MAXNAMELEN    255        /* maximum filename length */
  1372. X/* NOTE:  not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */
  1373. X
  1374. Xstruct direct                /* data from read()/_getdirentries() */
  1375. X    {
  1376. X    unsigned long    d_fileno;    /* unique ident of entry */
  1377. X    unsigned short    d_reclen;    /* length of this record */
  1378. X    unsigned short    d_namlen;    /* length of string in d_name */
  1379. X    char        d_name[MAXNAMELEN+1];    /* NUL-terminated filename */
  1380. X    /* typically shorter */
  1381. X    };
  1382. X
  1383. X/*
  1384. X    The DIRSIZ macro gives the minimum record length which will hold the
  1385. X    directory entry.  This requires the amount of space in a (struct
  1386. X    direct) without the d_name field, plus enough space for the name with a
  1387. X    terminating NUL character, rounded up to a (long) boundary.
  1388. X
  1389. X    (Note that Berkeley didn't properly compensate for struct padding,
  1390. X    but we nevertheless have to use the same size as the actual system.)
  1391. X*/
  1392. X
  1393. X#define    DIRSIZ( dp )    ((sizeof(struct direct) - (MAXNAMELEN+1) \
  1394. X            + sizeof(long) + (dp)->d_namlen) \
  1395. X            / sizeof(long) * sizeof(long))
  1396. END_OF_sys._dir.h
  1397. if test 2977 -ne `wc -c <sys._dir.h`; then
  1398.     echo shar: \"sys._dir.h\" unpacked with wrong size!?
  1399. fi
  1400. # end of overwriting check
  1401. fi
  1402. echo shar: Extracting \"sys.dirent.h\" \(980 characters\)
  1403. if test -f sys.dirent.h ; then 
  1404.   echo shar: Will not over-write existing file \"sys.dirent.h\"
  1405. else
  1406. sed "s/^X//" >sys.dirent.h <<'END_OF_sys.dirent.h'
  1407. X/*
  1408. X    <sys/dirent.h> -- file system independent directory entry (SVR3)
  1409. X
  1410. X    last edit:    25-Apr-1987    D A Gwyn
  1411. X
  1412. X    prerequisite:    <sys/types.h>
  1413. X*/
  1414. X
  1415. Xstruct dirent                /* data from getdents()/readdir() */
  1416. X    {
  1417. X    long        d_ino;        /* inode number of entry */
  1418. X    off_t        d_off;        /* offset of disk directory entry */
  1419. X    unsigned short    d_reclen;    /* length of this record */
  1420. X    char        d_name[1];    /* name of file */    /* non-POSIX */
  1421. X    };
  1422. X
  1423. X/* The following nonportable ugliness could have been avoided by defining
  1424. X   DIRENTSIZ and DIRENTBASESIZ to also have (struct dirent *) arguments. */
  1425. X#define    DIRENTBASESIZ        (((struct dirent *)0)->d_name \
  1426. X                - (char *)&((struct dirent *)0)->d_ino)
  1427. X#define    DIRENTSIZ( namlen )    ((DIRENTBASESIZ + sizeof(long) + (namlen)) \
  1428. X                / sizeof(long) * sizeof(long))
  1429. X
  1430. X/* DAG -- the following was moved from <dirent.h>, which was the wrong place */
  1431. X#define    MAXNAMLEN    512        /* maximum filename length */
  1432. X
  1433. X#ifndef NAME_MAX
  1434. X#define    NAME_MAX    (MAXNAMLEN - 1)    /* DAG -- added for POSIX */
  1435. X#endif
  1436. END_OF_sys.dirent.h
  1437. if test 980 -ne `wc -c <sys.dirent.h`; then
  1438.     echo shar: \"sys.dirent.h\" unpacked with wrong size!?
  1439. fi
  1440. # end of overwriting check
  1441. fi
  1442. echo shar: Extracting \"telldir.c\" \(794 characters\)
  1443. if test -f telldir.c ; then 
  1444.   echo shar: Will not over-write existing file \"telldir.c\"
  1445. else
  1446. sed "s/^X//" >telldir.c <<'END_OF_telldir.c'
  1447. X/*
  1448. X    telldir -- report directory stream position
  1449. X
  1450. X    last edit:    25-Apr-1987    D A Gwyn
  1451. X
  1452. X    NOTE:    4.nBSD directory compaction makes seekdir() & telldir()
  1453. X        practically impossible to do right.  Avoid using them!
  1454. X*/
  1455. X
  1456. X#include    <sys/errno.h>
  1457. X#include    <sys/types.h>
  1458. X#include    <dirent.h>
  1459. X
  1460. Xextern off_t    lseek();
  1461. X
  1462. Xextern int    errno;
  1463. X
  1464. X#ifndef SEEK_CUR
  1465. X#define    SEEK_CUR    1
  1466. X#endif
  1467. X
  1468. Xoff_t
  1469. Xtelldir( dirp )                /* return offset of next entry */
  1470. X    DIR    *dirp;            /* stream from opendir() */
  1471. X    {
  1472. X    if ( dirp == NULL || dirp->dd_buf == NULL )
  1473. X        {
  1474. X        errno = EFAULT;
  1475. X        return -1;        /* invalid pointer */
  1476. X        }
  1477. X
  1478. X    if ( dirp->dd_loc < dirp->dd_size )    /* valid index */
  1479. X        return ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off;
  1480. X    else                /* beginning of next directory block */
  1481. X        return lseek( dirp->dd_fd, (off_t)0, SEEK_CUR );
  1482. X    }
  1483. END_OF_telldir.c
  1484. if test 794 -ne `wc -c <telldir.c`; then
  1485.     echo shar: \"telldir.c\" unpacked with wrong size!?
  1486. fi
  1487. # end of overwriting check
  1488. fi
  1489. echo shar: Extracting \"testdir.c\" \(837 characters\)
  1490. if test -f testdir.c ; then 
  1491.   echo shar: Will not over-write existing file \"testdir.c\"
  1492. else
  1493. sed "s/^X//" >testdir.c <<'END_OF_testdir.c'
  1494. X/*
  1495. X    testdir -- basic test for C library directory access routines
  1496. X
  1497. X    last edit:    25-Apr-1987    D A Gwyn
  1498. X*/
  1499. X
  1500. X#include    <sys/types.h>
  1501. X#include    <stdio.h>
  1502. X#include    <dirent.h>
  1503. X
  1504. Xextern void    exit();
  1505. Xextern int    strcmp();
  1506. X
  1507. Xmain( argc, argv )
  1508. X    int            argc;
  1509. X    register char        **argv;
  1510. X    {
  1511. X    register DIR        *dirp;
  1512. X    register struct dirent    *dp;
  1513. X    int            nerrs = 0;    /* total not found */
  1514. X
  1515. X    if ( (dirp = opendir( "." )) == NULL )
  1516. X        {
  1517. X        (void)fprintf( stderr, "Cannot open \".\" directory\n" );
  1518. X        exit( 1 );
  1519. X        }
  1520. X
  1521. X    while ( --argc > 0 )
  1522. X        {
  1523. X        ++argv;
  1524. X
  1525. X        while ( (dp = readdir( dirp )) != NULL )
  1526. X            if ( strcmp( dp->d_name, *argv ) == 0 )
  1527. X                {
  1528. X                (void)printf( "\"%s\" found.\n", *argv );
  1529. X                break;
  1530. X                }
  1531. X
  1532. X        if ( dp == NULL )
  1533. X            {
  1534. X            (void)printf( "\"%s\" not found.\n", *argv );
  1535. X            ++nerrs;
  1536. X            }
  1537. X
  1538. X        rewinddir( dirp );
  1539. X        }
  1540. X
  1541. X    (void)closedir( dirp );
  1542. X    exit( nerrs );
  1543. X    }
  1544. END_OF_testdir.c
  1545. if test 837 -ne `wc -c <testdir.c`; then
  1546.     echo shar: \"testdir.c\" unpacked with wrong size!?
  1547. fi
  1548. # end of overwriting check
  1549. fi
  1550. echo shar: End of shell archive.
  1551. exit 0
  1552.